#include "bonderdispatcher.h"

BonderDispatcher::BonderDispatcher(MasterMotionManager *masterMotionManager,
                                   BonderBasicConfig *bonderBasicConfig,
                                   BasicElementFactory *motionElementFactory)
    : masterMotionManager(masterMotionManager),
      bonderBasicConfig(bonderBasicConfig),
      motionElementFactory(motionElementFactory)
{
    uphHelper = new UPHHelper();

    whState = new WorkHolderState();
    whStateStoreFile = new ConfigFile("WorkHolderState", whState,
                                      QString("%1/WorkHolderState.json").arg(Worker::getWorkerConfigDir()));
    whStateStoreFile->populate();

    if (bonderBasicConfig->sensorTrayElevatorAttached())
    {
        steConfig = new SensorTrayElevatorConfig();
        steConfigFile = new ConfigFile("SensorTrayElevatorConfig", steConfig,
                                       QString("%1/SensorTrayElevatorConfig.json").arg(Worker::getWorkerConfigDir()));
        steConfigFile->populate();
        stie = new SensorTrayInputElevator(steConfig);
        stoe = new SensorTrayOutputElevator(steConfig);
        registerWorker(stie);
        registerWorker(stoe);
    }

    laserConfig = new LaserConfig();
    laserConfigFile = new ConfigFile("laserConfig", laserConfig, "config/laserConfig.json");
    laserConfigFile->populate();
    laserDriver = new LaserDriver(laserConfig->serialPortConfig());
    leftLaser = new HTG1Laser(laserDriver, laserConfig->leftLaserConfig());
    rightLaser = new HTG1Laser(laserDriver, laserConfig->rightLaserConfig());
    sensorTrayConfig = new TrayConfig();
    sensorTrayConfigFile = new ConfigFile("SensorTrayConfig", sensorTrayConfig,
                                          QString("%1/SensorTrayConfig.json").arg(Worker::getWorkerConfigDir()));
    sensorTrayConfigFile->populate();
    sensorTrayMap = new SensorTrayMap(sensorTrayConfig, "DispWHSensorTrayMap",
                                      QString("%1/DispWHSensorTrayMap.json").arg(Worker::getWorkerConfigDir()));
    dispCommonConfig = new DispenseHeadCommonConfig();
    dispCommonConfigFile = new ConfigFile("DispenseCommonConfig", dispCommonConfig,
                                          QString("%1/DispenseCommonConfig.json").arg(Worker::getWorkerConfigDir()));
    dispCommonConfigFile->populate();
    leftDispHead
        = new DispenseHead(true, dispCommonConfig, leftLaser, sensorTrayConfig, sensorTrayMap, motionElementFactory);
    rightDispHead
        = new DispenseHead(false, dispCommonConfig, rightLaser, sensorTrayConfig, sensorTrayMap, motionElementFactory);
    leftDispHead->setAnotherDispHead(rightDispHead);
    rightDispHead->setAnotherDispHead(leftDispHead);
    dispWorkHolder
        = new DispenseWorkHolder(sensorTrayConfig, sensorTrayMap, whState, leftDispHead, rightDispHead, stie);

    sensorTrayConveyer = new SensorTrayConveyer(stoe);
    bonderWorkHolder = new BonderWorkHolder(sensorTrayConfig, whState, sensorTrayConveyer);

    ltModuleConfig = new LensTrayModuleConfig();
    ltModuleConfigFile = new ConfigFile("LensTrayModuleConfig", ltModuleConfig,
                                        QString("%1/LensTrayModuleConfig.json").arg(Worker::getWorkerConfigDir()));
    ltModuleConfigFile->populate();

    ltModuleState = new LensTrayModuleState();
    ltModuleStateStoreFile = new ConfigFile("LensTrayModuleState", ltModuleState,
                                            QString("%1/LensTrayModuleState.json").arg(Worker::getWorkerConfigDir()));
    ltModuleStateStoreFile->populate();

    lensTrayConfig = new TrayConfig();
    lensTrayConfigFile = new ConfigFile("LensTrayConfig", lensTrayConfig,
                                        QString("%1/LensTrayConfig.json").arg(Worker::getWorkerConfigDir()));
    lensTrayConfigFile->populate();

    lensTrayMap = new LensTrayMap(lensTrayConfig, QString("%1/LensTrayMap.json").arg(Worker::getWorkerConfigDir()));
    lensTrayMagazine = new LensTrayMagazine(ltModuleConfig, ltModuleState);
    lensTrayBuffer = new LensTrayBuffer(ltModuleConfig, ltModuleState, lensTrayMagazine);
    lensTrayLoader = new LensTrayLoader(ltModuleConfig, ltModuleState, lensTrayMagazine, lensTrayBuffer, lensTrayConfig,
                                        lensTrayMap);

    bonderHead = new BonderHead(sensorTrayConfig, lensTrayConfig, bonderWorkHolder, lensTrayLoader, uphHelper);

    lensTrayLoader->setBHConfig(bonderHead->getBhConfig());
    pressureMonitor = new PressureMonitor();

    registerWorker(dispWorkHolder);
    registerWorker(leftDispHead);
    registerWorker(rightDispHead);
    registerWorker(bonderWorkHolder);
    registerWorker(sensorTrayConveyer);
    registerWorker(lensTrayMagazine);
    registerWorker(lensTrayBuffer);
    registerWorker(lensTrayLoader);
    registerWorker(bonderHead);
    registerWorker(pressureMonitor);
}

void BonderDispatcher::setContextProperty(QQmlApplicationEngine &engine)
{
    if (bonderBasicConfig->sensorTrayElevatorAttached())
    {
        engine.rootContext()->setContextProperty("steConfig", steConfig);
        engine.rootContext()->setContextProperty("stie", stie);
        engine.rootContext()->setContextProperty("stoe", stoe);
    }

    engine.rootContext()->setContextProperty("uphHelper", uphHelper);

    engine.rootContext()->setContextProperty("laserSerialPortConfig", laserConfig->serialPortConfig());
    engine.rootContext()->setContextProperty("leftLaserConfig", laserConfig->leftLaserConfig());
    engine.rootContext()->setContextProperty("rightLaserConfig", laserConfig->rightLaserConfig());
    engine.rootContext()->setContextProperty("leftLaser", leftLaser);
    engine.rootContext()->setContextProperty("rightLaser", rightLaser);

    engine.rootContext()->setContextProperty("sensorTrayConfig", sensorTrayConfig);
    engine.rootContext()->setContextProperty("dispWorkHolder", dispWorkHolder);
    engine.rootContext()->setContextProperty("dwhTrayMap", dispWorkHolder->getTrayMap());
    engine.rootContext()->setContextProperty("leftDispHead", leftDispHead);
    engine.rootContext()->setContextProperty("rightDispHead", rightDispHead);
    engine.rootContext()->setContextProperty("dispCommonConfig", dispCommonConfig);
    engine.rootContext()->setContextProperty("dispenserConfig", dispCommonConfig->dispenserConfig());
    engine.rootContext()->setContextProperty("flyDispensingConfig", dispCommonConfig->xtFlyDispensingConfig());
    engine.rootContext()->setContextProperty("laserToCameraOffsetCaliParam",
                                             dispCommonConfig->laserToCameraOffsetCaliParam());
    engine.rootContext()->setContextProperty("glueCheckParam", dispCommonConfig->glueCheckParam());
    engine.rootContext()->setContextProperty("dispWHConfig", dispWorkHolder->getDispWHConfig());
    engine.rootContext()->setContextProperty("leftDHConfig", leftDispHead->getDhConfig());
    engine.rootContext()->setContextProperty("rightDHConfig", rightDispHead->getDhConfig());

    engine.rootContext()->setContextProperty("bwhConfig", bonderWorkHolder->getBwhConfig());
    engine.rootContext()->setContextProperty("stcConfig", sensorTrayConveyer->getStcConfig());
    engine.rootContext()->setContextProperty("bonderWorkHolder", bonderWorkHolder);
    engine.rootContext()->setContextProperty("bwhTrayMap", bonderWorkHolder->getTrayMap());
    engine.rootContext()->setContextProperty("postBondData", bonderWorkHolder->getPostBondDataAnalysis());
    qmlRegisterType<SensorTrayMaterialData>("SensorTrayMaterialData", 1, 0, "SensorTrayMaterialData");

    engine.rootContext()->setContextProperty("ltModuleConfig", ltModuleConfig);
    engine.rootContext()->setContextProperty("lensTrayConfig", lensTrayConfig);
    engine.rootContext()->setContextProperty("lensTrayMagazine", lensTrayMagazine);
    engine.rootContext()->setContextProperty("lensTrayBuffer", lensTrayBuffer);
    engine.rootContext()->setContextProperty("lensTrayLoader", lensTrayLoader);
    engine.rootContext()->setContextProperty("ltlTrayMap", lensTrayLoader->getTrayMap());

    engine.rootContext()->setContextProperty("bonderHead", bonderHead);
    engine.rootContext()->setContextProperty("bhConfig", bonderHead->getBhConfig());
    engine.rootContext()->setContextProperty("pickPlaceConfig", bonderHead->getBhConfig()->pickPlaceConfig());
    engine.rootContext()->setContextProperty("ltCameraToUplookCameraOffset",
                                             bonderHead->getBhConfig()->ltCameraToUplookCameraOffset());
    engine.rootContext()->setContextProperty("stCameraToUplookCameraOffset",
                                             bonderHead->getBhConfig()->stCameraToUplookCameraOffset());
    engine.rootContext()->setContextProperty("stCameraToUplookCameraOffsetOfEachRow",
                                             bonderHead->getBhConfig()->stCameraToUplookCameraOffsetOfEachRow());
    engine.rootContext()->setContextProperty("stSideTwoDimensionCalibrationParam",
                                             bonderHead->getBhConfig()->stSideTwoDimensionCalibrationParam());
    engine.rootContext()->setContextProperty("ltSideTwoDimensionCalibrationParam",
                                             bonderHead->getBhConfig()->ltSideTwoDimensionCalibrationParam());
    engine.rootContext()->setContextProperty("bhSafetyPosNearLT", bonderHead->getBhConfig()->safetyPosNearLT());
    engine.rootContext()->setContextProperty("bhSafetyPosNearST", bonderHead->getBhConfig()->safetyPosNearST());
}

void BonderDispatcher::handleInit()
{
    VisionManager::getIns().postInit();
    masterMotionManager->initMotionManagers();
}

void BonderDispatcher::handleStart()
{
    VisionManager::getIns().stopAllCameraShowRealtimeImage();
    uphHelper->start();
}

void BonderDispatcher::handlePause()
{
    QThread::msleep(
        50);    // masterMotionManager lived in main thread. Sleep to make main thread handle state transition first.
    masterMotionManager->pause();
}

void BonderDispatcher::handleContinue()
{
    masterMotionManager->unPause();
}

void BonderDispatcher::handleAbort()
{
    masterMotionManager->handleAbort();
}

void BonderDispatcher::handleReset()
{
    masterMotionManager->handleReset();
}

void BonderDispatcher::preHome() {}
